#include "attachobjecteffect.h"
#include "actorbase.h"
#include "drawable.h"
#include "transformableactor.h"
#include <osg\Node>
#include <osg\Camera>
#include "manipulatormanager.h"
#include "attachobjectmanipulator.h"
#include "pickmanager.h"

namespace ControlCenter
{
	AttachObjectUpdateCallback::AttachObjectUpdateCallback(AttachObjectEffect* ef)
	{
		_ef = ef ;
	}

	void AttachObjectUpdateCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
	{
		if(!_ef)
		{
			traverse(node,nv);
			return;
		}
		_ef->update();
		if(_nestedCallback.valid())
			 (*_nestedCallback)(node,nv);
		traverse(node,nv);
	}

	AttachObjectEffect::AttachObjectEffect(ManipulatorManager* mm,osg::Camera* camera):_manipulatorManager(mm)
		,_transformActor(NULL),_setupCallback(false),_attachObjectCamera(camera)
		,_distance(6.0f),_angleXY(0),_angleXZ(0)/*,_attachObjectUsingCallback(NULL)*/
	{
		_updateCallback = new AttachObjectUpdateCallback(this);
	}

	AttachObjectEffect::~AttachObjectEffect()
	{}

	void AttachObjectEffect::buildPropertyMap()
	{
		EffectBase::buildPropertyMap();
	}

	void AttachObjectEffect::apply(CoreBase::ActorBase* actor)
	{
		if(_manipulatorManager!=NULL)
		{
			_attachObjectManipulator = dynamic_cast<AttachObjectManipulator*>(
					_manipulatorManager->getManipulatorByMode(CLASS_MANIPULATOR_ATTACHOBJECT));
			if(_attachObjectManipulator!=NULL)
			{
				_transformActor =  dynamic_cast<VrDataCore::TransformableActor*>(actor);
				if(_transformActor!=NULL)
				{
					if(!_setupCallback)
					{
						_attachObjectCamera->addUpdateCallback(_updateCallback);
						_setupCallback = true;
					}
					osg::Vec3 end = _transformActor->getTranslation();
					//osg::Vec3 start(end + osg::Vec3(0,0,50));
					//osg::Vec3 point,normal;
					//VrDataCore::PickManager::GetInstance().getLineSegmentIntersectResult(start,end,point,normal,NODE_MASK_ALL);
					//point = point + osg::Vec3(0,0,_height);
					//osg::Vec3 absolutelytrans = VrDataCore::LayersManager::GetInstance().getAbsolutelyTranslate(findactor);
					float anglexz = osg::DegreesToRadians(float(_angleXZ));
					float cy = _distance*cos(osg::DegreesToRadians(float(_angleXY)))*sin(anglexz);
					float cx = _distance*cos(osg::DegreesToRadians(float(_angleXY)))*cos(anglexz);
					float cz = _distance*sin(osg::DegreesToRadians(float(_angleXY)));
					osg::Vec3 upval = osg::Quat(osg::DegreesToRadians(float(_angleXY)),osg::Vec3(0.0f,-1.0f,0.0f))*osg::Vec3(0.0f,0.0f,1.0f);
					osg::Vec3 eye(osg::Vec3(cx,cy,cz));
					eye.z() = eye.z()<1?1:eye.z();
					osg::Vec3 up = osg::Quat(anglexz,osg::Vec3(0.0f,0.0f,1.0f))*upval;
					_attachObjectManipulator->setLookAt(eye+end + _offset,end + _offset,up,_distance,false);
					//_attachObjectManipulator->setLookAt(end + osg::Vec3(0,0,point.z()),
					//	end + osg::Vec3(0,0,point.z()) + osg::Quat(osg::DegreesToRadians(_transformActor->getRotation().z()+_angleXZ),
					//	osg::Vec3(0,0,1))*osg::Vec3(1,0,0),osg::Vec3(0,0,1),1,false);
					//osg::Vec3 center = _transformActor->getDrawable()->getBoundingBox().center();
					//osg::Vec3 hei = osg::Vec3(center.x(),center.y(),_transformActor->getDrawable()->getBoundingBox().zMax()+2);
					_attachObjectManipulator->objectTransformInitThis(eye,
						end,_offset,_transformActor->getRotation(),up);
					VrDataCore::EffectBase::apply(actor);
				}
			}
		}
	}

	void AttachObjectEffect::unApply(CoreBase::ActorBase* actor)
	{
		if(isIdle())
			return;
		if(actor!=NULL && actor->getDrawable()!=NULL && actor->getDrawable()->getOSGNode()!=NULL)
		{
			_attachObjectCamera->removeUpdateCallback(_updateCallback);
			_setupCallback = false;
			_attachObjectManipulator->setOperatorObjectVector(QVector<CoreBase::ActorBase*>());
		}
		VrDataCore::EffectBase::unApply(actor);
	}

	void AttachObjectEffect::setInitial(const osg::Vec3& offset,int distance,int anglexy, int anglexz)
	{
		_distance = distance;
		_angleXY = anglexy;
		_angleXZ = anglexz;
		_offset = offset;
	}

	osg::ref_ptr<CoreBase::ActorBase> AttachObjectEffect::clone()
	{
		osg::ref_ptr<ActorBase> clone = ActorBase::clone();
		return clone;
	}

	void AttachObjectEffect::update()
	{
		if(_transformActor!=NULL)
		{
			_attachObjectManipulator->setObjectTransform(_transformActor->getTranslation(),_transformActor->getRotation());
		}
	}
}